package com.base.monitor.module.biz.service.collect.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.base.monitor.framework.exception.CustomerException;
import com.base.monitor.framework.result.PageResult;
import com.base.monitor.framework.util.ConcurrentUtil;
import com.base.monitor.framework.util.CustomerUtils;
import com.base.monitor.framework.util.DiskUtils;
import com.base.monitor.model.enums.code.impl.common.ResultCode;
import com.base.monitor.model.model.biz.collect.criteria.ChannelCriteria;
import com.base.monitor.model.model.biz.collect.dto.HandleChannelDto;
import com.base.monitor.model.model.biz.collect.entity.Blacklist;
import com.base.monitor.module.biz.context.ClientContext;
import com.base.monitor.module.biz.properties.NetworkProperties;
import com.base.monitor.module.biz.service.collect.ChannelService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
@EnableConfigurationProperties(NetworkProperties.class)
public class ChannelServiceImpl implements ChannelService {

    @Autowired
    private DiskUtils diskUtils;

    @Autowired
    private NetworkProperties networkProperties;

    /**
     * 分页条件查询信道信息
     * @param channelCriteria 查询条件
     * @return
     */
    @Override
    public PageResult<ClientContext.ChannelInfo> page(ChannelCriteria channelCriteria) {
        List<ClientContext.ChannelInfo> channelList = ClientContext.getChannelList();

        if (StrUtil.isNotBlank(channelCriteria.getIp())) {
            channelList = channelList.stream()
                    .filter(item -> item.getIp().contains(channelCriteria.getIp()))
                    .collect(Collectors.toList());
        }

        if (StrUtil.isNotBlank(channelCriteria.getCommand())) {
            channelList = channelList.stream()
                    .filter(item -> item.getCommand().contains(channelCriteria.getCommand()))
                    .collect(Collectors.toList());
        }

        // 排序
        if (CollectionUtil.isNotEmpty(channelList)) {
            channelList.sort((item1, item2) -> item2.getConnectTime().compareTo(item1.getConnectTime()));
        }

        // 分页返回
        return new PageResult<>(channelList.size(), CustomerUtils
                .getSubListForPage(channelList, channelCriteria.getPage(), channelCriteria.getSize()));
    }

    /**
     * 强制下线指定信道
     * @param handleChannelDto 该信道的连接信息
     */
    @Override
    public ClientContext.ChannelInfo kick(HandleChannelDto handleChannelDto) {
        ClientContext.ChannelInfo channelInfo = ClientContext.getChannelInfoByCommand(handleChannelDto.getCommand());
        if (channelInfo == null) {
            throw new CustomerException(ResultCode.RETURN_DATA_NOT_FOUND, "强制下线时，对应的信道信息不存在");
        }
        ClientContext.removeClient(channelInfo.getCtx());
        log.error("客户端{}已经被强制下线", channelInfo.getIp());
        return channelInfo;
    }

    /**
     * 将指定信道加入黑名单
     * @param handleChannelDto 该信道的连接信息
     */
    @Override
    public void blacklist(HandleChannelDto handleChannelDto) {
        // 1.先踢了
        ClientContext.ChannelInfo channelInfo = this.kick(handleChannelDto);

        // 2.封装黑名单信息
        Blacklist black = new Blacklist(channelInfo.getCommand(), ConcurrentUtil.format(channelInfo.getConnectTime()));

        // 3.加入黑名单
        ClientContext.addBlacklist(black);

        // 4.再获取当前的黑名单信息
        List<String> collect = ClientContext.getBlacklist().stream().map(Blacklist::toString).collect(Collectors.toList());
        String blacklist = CollectionUtil.join(collect, ",");

        // 5.写入文件
        diskUtils.updatePropertiesFile("network.blacklist", blacklist);

        // 6.更新networkProperties
        networkProperties.setBlacklist(blacklist);
    }

    /**
     * 将指定信道从黑名单中移除
     *
     * @param handleChannelDto 该信道的连接信息
     */
    @Override
    public void cancel(HandleChannelDto handleChannelDto) {
        // 1.从黑名单中移除
        ClientContext.removeBlacklist(handleChannelDto.getCommand());

        // 2.再获取当前的黑名单信息
        List<String> collect = ClientContext.getBlacklist().stream().map(Blacklist::toString).collect(Collectors.toList());
        String blacklist = CollectionUtil.join(collect, ",");

        // 3.写入文件
        diskUtils.updatePropertiesFile("network.blacklist", blacklist);

        // 4.更新networkProperties
        networkProperties.setBlacklist(blacklist);
    }
}
